package com.prodog.database.loader;

import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.prodog.database.annotation.Wrapper;
import com.prodog.database.wrapper.AbstractDataWrapper;
import com.prodog.database.wrapper.DataWrapperCentral;
import com.prodog.database.wrapper.LocalDataWrapper;
import com.prodog.database.wrapper.MongoDataWrapper;
import com.prodog.utils.bean.SpringBeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j(topic = "游戏数据加载器")
@Order(3)
public class GameDataLoader implements CommandLineRunner {
    @Value("${game.rootPath}")
    private String gameRootPath;

    @Override
    public void run(String... args) {
        this.loadWrapper();
    }

    private void loadWrapper() {
        List<Object> wrapperObjs = SpringBeanUtils.getBeansByAnnotation(Wrapper.class);
        List<LocalDataWrapper> localWrappers = wrapperObjs.stream()
                .filter(wrapper -> wrapper instanceof LocalDataWrapper)
                .map(wrapper -> (LocalDataWrapper) wrapper)
                .collect(Collectors.toList());
        List<MongoDataWrapper> mongoDataWrappers = wrapperObjs.stream()
                .filter(wrapper -> wrapper instanceof MongoDataWrapper)
                .map(wrapper -> (MongoDataWrapper) wrapper)
                .collect(Collectors.toList());

        loadLocalDataWrapper(localWrappers);
        loadMongoDataWrapper(mongoDataWrappers);
    }

    private void loadMongoDataWrapper(List<MongoDataWrapper> mongoDataWrappers) {
        log.info("正在加载用户数据.........");
        for (MongoDataWrapper wrapper : mongoDataWrappers) {
            loadMongoDataWrapper(wrapper);
        }
        log.info("用户数据加载完毕！");
    }

    private void loadMongoDataWrapper(MongoDataWrapper wrapper) {
        Wrapper wrappAno = AnnotationUtils.findAnnotation(wrapper.getClass(), Wrapper.class);
        String module = wrappAno.module();
        setWrapperTypeClass(wrapper);
        DataWrapperCentral.pushWrapper(wrapper.getTypeClass(), wrapper);
        log.info("  [" + module + "]加载完成！");
    }

    private void loadLocalDataWrapper(List<LocalDataWrapper> localWrappers) {
        log.info("正在加载游戏数据.........");
        for (LocalDataWrapper wrapper : localWrappers) {
            loadLocalDataWrapper(wrapper);
        }
        log.info("游戏数据加载完毕！");
    }

    private void loadLocalDataWrapper(LocalDataWrapper wrapper) {
        Wrapper wrappAno = wrapper.getClass().getAnnotation(Wrapper.class);
        String path = wrappAno.path();
        String module = wrappAno.module();
        File dataPathFile = new File(gameRootPath, path);
        int loadNums = 0;
        wrapper.setDataPath(path);
        setWrapperTypeClass(wrapper);
        Map dataMap = new HashMap();
        Map pathMap = new HashMap();
        for (File file : dataPathFile.listFiles()) {
            String jsonStr = FileUtil.readUtf8String(file);
            Map<String, Object> jsonData = JSONUtil.toBean(jsonStr, Map.class);
            if (wrapper.getTypeClass() != null) {
                try {
                    Object data = JSONUtil.toBean(jsonStr, wrapper.getTypeClass());
                    dataMap.put(jsonData.get("id"), data);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                dataMap.put(jsonData.get("id"), jsonData);
            }
            pathMap.put(jsonData.get("id"), file.getAbsolutePath());
            loadNums++;
        }
        wrapper.setDataMap(dataMap);
        wrapper.setPathMap(pathMap);
        DataWrapperCentral.pushWrapper(wrapper.getTypeClass(), wrapper);
        log.info("  [" + module + "]加载完成！共" + loadNums + "个");
    }

    private void setWrapperTypeClass(AbstractDataWrapper wrapper) {
        Type superClazz = wrapper.getClass().getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) superClazz;
        if (parameterizedType.getActualTypeArguments().length > 0) {
            wrapper.setTypeClass((Class) parameterizedType.getActualTypeArguments()[0]);
        }
    }
}
